
package com.beiding;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
import org.springframework.session.Session;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

@Configuration
public class TestWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        //添加用户
        auth.inMemoryAuthentication().withUser("abc").password(passwordEncoder().encode("123")).authorities("user")
                .and().withUser("ding").password(passwordEncoder().encode("123")).authorities("user");



    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/user/login")
                .successHandler(new SavedRequestAwareAuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {

                        //在认证成功后将用户名放入session中
                        request.getSession().setAttribute("user.name", authentication.getName());
                        request.getSession().setAttribute("user.authorities", authentication.getAuthorities());




                        //为了实现排他登录.直接删除该用户的其他session

                        Map<String, ?> map = repository.findByPrincipalName(authentication.getName());

                        if (map != null)

                            map.forEach((s, o) -> {

                                Session session = (Session) o;


                                final Set<String> names = session.getAttributeNames();


                                names.forEach(s1 -> {


                                    System.out.println(s1 + ": " + session.getClass());


                                });




                                repository.deleteById(s);




                            });

                        super.onAuthenticationSuccess(request, response, authentication);
                    }
                })
                .permitAll()
                .and().csrf().disable();

        http.sessionManagement()
                .sessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy(
                        sessionRegistry
                ))
                .invalidSessionUrl("/login")
                .maximumSessions(1)
                .sessionRegistry(sessionRegistry)
                .expiredUrl("/login");


    }

    private SpringSessionBackedSessionRegistry sessionRegistry;

    private RedisOperationsSessionRepository repository;


    @Bean
    SessionRegistry sessionRegistry(RedisOperationsSessionRepository repository) {
        sessionRegistry = new SpringSessionBackedSessionRegistry<>(repository);
        this.repository = repository;
        return sessionRegistry;
    }






}


//ConfigureNotifyKeyspaceEventsAction  keyspace notification